의존성 주입(Dependency Injection)

✒️ 2025-06-30 11:32 내용 수정


참고 자료 : Spring Dependency Injection, Spring Using @Autowired, nova_dev's Spring 스프링 의존 자동 주입(Auto Injection)이란

의존성 주입(Dependency Injection)

Spring Container가 각 객체간의 의존 관계를 개발자가 정의한 Bean 등록 정보를 바탕으로 자동 주입하는 기능


의존성 주입 설정

1. XML 방식

<!-- XML 설정 예시 -->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
         http://www.springframework.org/schema/beans 
         https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="anotherExampleBean" class="examples.AnotherBean"/>
    <bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
    <bean id="exampleBean" class="examples.ExampleBean">
        <!-- setter 주입 -->
        <property name="beanOne">
            <ref bean="anotherExampleBean"/>
        </property>
        <property name="beanTwo" ref="yetAnotherBean"/>
    </bean>
</beans>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
         http://www.springframework.org/schema/beans 
         https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="anotherExampleBean" class="examples.AnotherBean"/>
    <bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
    <bean id="exampleBean" class="examples.ExampleBean">
        <!-- 생성자 주입 -->
        <constructor-arg ref="anotherExampleBean"/>
        <constructor-arg ref="yetAnotherBean"/>
    </bean>
</beans>

2. Annotation 방식

public class Test {
	private final TestBean testBean;
	
	@Autowired
	public Test(TestBean testBean) {
		this.testBean = testBean;
	}
}

의존성 주입 방법

1. 필드 주입(Field Injection)

public class Computer {
	@Autowired
	private CPU cpu;

	public CPU getCpu() {
		return cpu;
	}
}

필드 주입의 문제

2. 수정자 주입(Setter Injection)

public class Computer {
	private CPU cpu;

	@Autowired
	public void setCpu(CPU cpu) {
		this.cpu = cpu;
	}
}

3. 생성자 주입(Constructor Injection)

public class Computer {
	private CPU cpu;

	@Autowired
	public Computer(CPU cpu) {
		this.cpu = cpu;
	}
}

객체 구분을 위한 @Qualifier

// interface를 만든다.
package com.example.first.qualifier;

public interface Computer {
	public int getScreenWidth();
}
package com.example.first.qualifier;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
@Qualifier("desktop") // Qualifier를 추가
// Computer를 구현한 클래스 1
public class Desktop implements Computer{ 

	@Override
	public int getScreenWidth() {
		return 1920;
	}
}
package com.example.first.qualifier;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

@Component
@Qualifier("laptop") // Qualifier를 추가
// Computer를 구현한 클래스 2
public class Laptop implements Computer{ 

	@Override
	public int getScreenWidth() {
		return 1600;
	}
}
package com.example.first.qualifier;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class ComputerTest {  
	
	@Autowired
	@Qualifier("desktop")
	Computer computer; // Desktop 클래스로 선택된다

	@Test
	public void computerTest() {
		System.out.println(computer.getScreenWidth());
	}
}
1920
package com.example.first.qualifier;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;

import lombok.extern.slf4j.Slf4j;

@SpringBootTest
@Slf4j // 테스트
public class ComputerTest {  
	
	@Autowired
	@Qualifier("laptop")
	Computer computer; // Laptop 클래스로 선택된다

	@Test
	public void computerTest() {
		System.out.println(computer.getScreenWidth());
	}
}
1600
@Component
@Qualifier("laptop")
@Primary // Qualifier 중 기본 클래스로 설정
public class Laptop implements Computer{ 

	@Override
	public int getScreenWidth() {
		return 1600;
	}
}
package com.example.first.qualifier;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class ComputerTest {  
	
	@Autowired
	Computer computer; // Laptop 클래스로 선택된다

	@Test
	public void computerTest() {
		System.out.println(computer.getScreenWidth());
	}
}
1600

DI를 이용한 MVC 흐름

di flow.png

0. 프로젝트 설정

1. BoardDAO 인터페이스

package dao;

import java.util.List;

public interface BoardDAO {
	
	// DAO (Data Access Object) 
	// 기본적으로 CRUD 기능을 가지고 있다.
	// 나중에 사용할 추상 메소드 주입
	int insert(Object ob);
	
	List<Object> selectList();
	
	int update(Object ob);
	
	int delete(int idx);
}

2. BoardDAOImpl 클래스

package dao;

import java.util.ArrayList;
import java.util.List;

public class BoardDAOImpl implements BoardDAO{

	@Override
	public int insert(Object ob) {
		return 0;
	}

	@Override
	public List<Object> selectList() {
		List<Object> list = new ArrayList<Object>();
		list.add("사과");
		list.add("복숭아");
		list.add("수박");
		list.add("참외");
		list.add("바나나");
		return list;
	}

	@Override
	public int update(Object ob) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public int delete(int idx) {
		// TODO Auto-generated method stub
		return 0;
	}
	
}

3. BoardService 인터페이스

package service;

import java.util.List;

// service에서 DB에 여러번 접근할 때 로직 하나를 추가해서
// 일을 합쳐서 수행할 수 있도록 만듦
public interface BoardService {
	
	List<Object> selectList();
}

4. BoardServiceImpl 클래스

package service;

import java.util.List;

import dao.BoardDAOImpl;

public class BoardServiceImpl implements BoardService{

	BoardDAOImpl dao;
	
	public BoardServiceImpl(BoardDAOImpl dao) {
		this.dao = dao;
	}
	
	@Override
	public List<Object> selectList() {
		
		// 생성자 주입으로 전달받은 BoardDAOImpl의 selectList()
		return dao.selectList();
	}

}

5. RootContext에 Bean 객체 생성

package config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import dao.BoardDAOImpl;
import service.BoardServiceImpl;

@Configuration
public class RootContext {
	
	@Bean
	public BoardDAOImpl dao() {
		return new BoardDAOImpl();
	}
	
	@Bean
	public BoardServiceImpl service(BoardDAOImpl dao) {
		// 생성자 주입
		// 생성자를 만들어 놓은 후 필요한 객체에 넣음
		return new BoardServiceImpl(dao);
	}
}

6. BoardController 클래스

package com.nogroup.di;

import java.util.List;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import service.BoardServiceImpl;

// Controller 역할을 하는 클래스에 반드시 Controller Annotation 추가
@Controller
public class BoardController {

	BoardServiceImpl service;
	
	// 수정자 주입을 위한 setter 메소드 생성
	public void setService(BoardServiceImpl service) {
		this.service = service;
	}
	
	@RequestMapping("/board/list")
	public String select(Model model) {
		List<Object> list = service.selectList();
		model.addAttribute("list", list);
		return "board_list";
	}
}

7. ServletContext에 BoardController 객체 생성

package config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

import com.nogroup.di.BoardController;

import service.BoardServiceImpl;

@Configuration
@EnableWebMvc
@ComponentScan("com.nogroup.di")
public class ServletContext implements WebMvcConfigurer{
	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
	}
	
	@Bean
	public InternalResourceViewResolver resolver() {
		InternalResourceViewResolver resolver = new InternalResourceViewResolver();
		resolver.setViewClass(JstlView.class);
		resolver.setPrefix("/WEB-INF/views/");
		resolver.setSuffix(".jsp");
		return resolver;
	}
	
	// Controller 객체만 ServletContext에 만든다
	@Bean
	public BoardController boardController(BoardServiceImpl service) {
		BoardController bc = new BoardController();
		bc.setService(service);
		return bc;
	}
}

8. 정보를 보여줄 board_list.jsp 생성

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>과일목록</h1>
	
	<c:forEach var="vo" items="${list}">
		${vo}<br>
	</c:forEach>
</body>
</html>

di 10.png